home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: MegaDisc
/
MegaDisc 06 (1988)(MegaDisc Digital Publishing)(AU)[m][WB].zip
/
MegaDisc 06 (1988)(MegaDisc Digital Publishing)(AU)[m][WB].adf
/
PROGRAMS
/
AboutAbort
< prev
next >
Wrap
Text File
|
1988-03-28
|
16KB
|
254 lines
ABORTCOMMAND
~~~~~~~~~~~~
written by Ken J. White (7th March 1988)
[ED. NOTE: This useful utility is a welcome addition to the system of
anyone fed up with those pesky software errors. Ken has also included
the source code with his contribution, and in this description gives
a very lucid explanation of how he programmed in MC68000 Assembly
Language. Necessary reading for would-be programmers. Ken might
provide us with another couple of useful commands for the next
issue, including an intelligent ASK command which will continue
processing a batch file after a specified period.]
************************************************************************
This is a handy little utility for anyone who is developing
software for the Amiga. It also has uses for those not inclined
to writing software. A quite common occurrence for those testing
programs is that the program finds itself in an endless loop,
never returning control back to the user. For a multitasking
computer such as the Amiga, all you have to do is write that
task off and continue in some other task that you started up
previously. The problem is that the misguided task will probably
be consuming a large proportion of the microprocessor time slices,
thus slowing everything else down (as if you had plenty of time
waste). Rather than reboot, you can now use ABORTCOMMAND to regain
control of a CLI task that is locked up by a faulty command. It
also can be used in cases where a command has produced THAT well
known requester (you know the one...... Software Error. Task
held...... etc)! In that case you get the task back! The requestor
remains, but is totally inactive, thus preventing that annoying
behaviour of the system ominously replacing it at the front in the
top left-hand corner every time you put a disk in a drive.
There are, however, limitations on the use of ABORTCOMMAND.
First, there must be either Workbench or another CLI active in
order to use ABORTCOMMAND. Thus it is common sense to have at
least two processes (Workbench and/or CLIs) active before any
programs are tested. ABORTCOMMAND can be accessed from either
a CLI or Workbench. Second, ABORTCOMMAND can be used to abort
CLI commands ONLY. It cannot be used to abort Workbench programs,
tasks in general, or interrupts. To abort these would require
information that is not readily available to the user. This is
especially true with Workbench programs. Third, ABORTCOMMAND
can only be used where multitasking and interrupts have not
been disabled by the faulty command or where a guru has not been
generated. More general, ABORTCOMMAND cannot be used when the
whole system has frozen, crashed, or died some other horrible
death. Fourth, ABORTCOMMAND does not perform any clean-up
operations except for what DOS normally does when a command
exits. Any memory, signals, traps, etc, that the command has
allocated will remain allocated. Any files, devices, windows,
libraries, etc, that the command opens will remain open. Any
tasks, processes, interrupts, etc, that have the command has
created, unless they can remove themselves, will remain. An
example was given above where an inactive requester remains.
Finally, the use of ABORTCOMMAND should NEVER be regarded as
completely safe. It will generally be operating in an unknown
environment where the effects of aborting a command is quite
unpredictable. Fortunately, most critical operations will be
performed with multitasking disabled, so that you will be
protected from the worst effects of unpredictability.
The use of ABORTCOMMAND is quite straightforward. Simply
type it as a CLI command or double-click it's icon. A window
will open and you will be asked to input the CLI number of the
command to abort. For commands initiated by RUN, this is the
CLI number generated by RUN, not of the CLI in which RUN was
performed. The name of the command will be printed and you will
be asked whether you wish to abort it. Type "y","Y","yes", or
in fact anything that starts with a "y" or "Y", and the named
command will be aborted unless some problem is found. The program
will then exit. If the CLI number input was found to be invalid,
or you typed something that didn't start with "y" or "Y" when
asked whether to abort, or some other problem was encountered, you
will be asked if you wish to exit. Again "y","Y" as the first
character will cause the program to exit, otherwise it will
restart by asking you to input a CLI number. On exit, regardless
of whether a command was aborted or not, the window will be closed
and the return code will be zero (no error). Errors that prevent
the window from being opened will generate a return code of 20
(fail). The aborted command will generate a return code of 100 but
no message.
Technical Information
~~~~~~~~~~~~~~~~~~~~~
This section is to give programmers and hackers in general more
information on how this utility operates and give a little insight
on other possible uses. Because these other uses are not currently
implemented, I have supplied the source code (MC68000 Assembly
Language) so that modifications may be made. An attempt was made
to make this code flexible so that modifications will not be too
difficult. The code has not been liberally interspersed with
comments, however, I believe that I have supplied sufficient
information to allow anyone who knows what they are doing to
easily understand and modify the code.
The code consists of four sections: AbortCommand, function,
subroutines, and donated_segment.
"AbortCommand" performs the initialisation procedure. This
consists of allocating and clearing 320 bytes of stack space,
obtaining the address of our task, then testing whether we are
running under Workbench or a CLI. If under Workbench, we wait for,
then obtain the message that Workbench has sent us. The address of
the predecessor segment to donated_segment is obtained using the
label, external_code, to identify the segment, donated_segment.
(This will be explained in greater detail below.). The DOS library
is then opened and if under CLI, the default output file handle is
obtained (for error messages). The CON: window is then opened.
Subroutine, function, (fully explained below) is performed.
"AbortCommand" also performs the finalisation procedure of closing
the window, closing the DOS library, and if run from Workbench,
replying to its message. Stack space is deallocated then we RTS
back to DOS. Open library and window errors are also handled.
"function" performs the real magic. First, it clears D7, which
is used internally, as a set of flags. Then, it asks for the CLI
number of the command to abort. All message output (except the
command name string) is handled the same way. The subroutine,
output_string, uses a message base address (in A0) and a message
number (in D0) to output a variable length null-terminated string
to the file handler (in D1) (the window). The message base address
corresponds to the start of the first message which is message
number 1. The subroutine, input_cli_num, inputs a decimal or
hexadecimal number of up to 8 digits. The use of the "$" character
immediately before the number (ie, no spaces) distinguishes a
hexadecimal from a decimal number. This allows the subroutine to
be used for inputing such data as task addresses, etc. The
subroutine converts the ASCII string to a binary value and returns
the result (or zero if invalid) in D0. "function" then disables
interrupts then tests the existance of the requested CLI. If it
exists, the task address of the CLI is determined and placed in
A1. This is compared with our task address. If different, the
Ready and Wait task lists are scanned in search of the task. If
not found, bit 30 of D7 will be set. If found in the Wait list,
bit 31 of D7 will be set (although this is not subsequently used).
Subroutine, command_name, is then performed. This routine tests
whether a command is currently loaded, if so, it copies the name
string to our input buffer, interrupts are enabled and the copied
name string is outputed. Otherwise, bit 29 of D7 is set, then
interrupts are enabled. "function" then asks whether you wish to
abort the command. (The function of subroutine, confirm_abort, was
adequately explained above.). Interrupts are then disabled.
Because of the period of enabled interrupts (and therefore,
multitasking) we cannot trust any of the information obtained
earlier. The CLI number is used to redetermine the task address
which is verified with the previously determined task address.
If it verifies as the same, the Ready and Wait task lists are
rescanned. If the task is not found, the state of bit 30 of D7 is
reversed. I try to take into consideration all possibilities,
including that of the task inadvertently removing itself from the
task lists. However, because the environment is unknown, we must
view tasks, that are not in the lists, with suspicion. The point
is that we base our decision of whether or not to abort it on the
result of both task list scans. A change, especially where the
task has moved back into the lists, suggests that the task may be
under external control and best left alone. Bit 30 of D7 is
tested. If 0, we assume the task has not moved (we fully expect
the task to interchange between Ready, Run, and Wait states and
thus ignore such changes except that bit 31 of D7 correctly
reflects the state), and if the task is not in the lists, we set
bit 30 of D7. "function" then obtains the address of the tail
segment of the command to abort, the stack pointer to the DOS
supplied return address, and the stack pointer to the task's
stored stack frame. In each case, a test is made to assure that
the command has not exited or is not in the process of exiting.
The address associated with the label, external_pc_cli, is
obtained and stored for later use. This address is, eventually,
to become the command's new program counter. Note that the
label corresponds to the same address as label, external_code.
However, I chose to use different labels for greater flexibility
in case modifications are made. The segment, donated_segment, is
then removed from our code's segment list and added to the tail
of the segment list of the command to abort. (An explanation of
why this is done is best deferred till later.). All the command
task's registers are transferred from the stored stack frame to
a data storage area within segment, donated_segment, then the
stored program counter is replaced and the stored status
register is cleared. The new stack pointer, which points to the
DOS supplied return address, is not stored within the task's
context but, rather, within the segment, donated_segment. This
was done to maintain flexibility should this code every be
modified. Finally the task is transferred to the TaskReady list
then the interrupts are enabled. The next time the task regains
the microprocessor, it will exit back to DOS. If any problems
were encountered along the way you will be asked if you wish to
exit. The subroutine, confirm_exit, is essentially the same as
subroutine, confirm_abort, except that a different message is
generated. "function" will either exit or restart from label,
function.
"subroutines" contain all the miscellaneous subroutines used
by our code. I believe an adequate description has been given.
If you wish to find out more, you will have to look at the code
itself.
"donated_segment" is the segment that is transferred to the
command's segment list. It contains the code to allow the
command to exit back to DOS. It also contains all of the task's
original registers and the task's new stack pointer. The task's
new stack pointer is utilised by the code so that at the entry
point, the entire task context is available, which it would not
have been if the stack pointer were altered by "function".
Because the command is aborted by altering the task's program
counter and allowing multitasking to take its course, thereby
forcing it to exiting via external_pc_cli, which is part of our
context, I had to consider the possibility of our program
exiting before the command to abort regains the microprocessor.
This would cause the program counter to point to invalid code,
resulting in a system crash. I decided to remove the segment,
"donated_segment", from our context and add it the context of
the command. By disowning the segment, our code can exit at any
time with a clear conscience. When the aborted command exits,
DOS will free the memory associated with the segment as if it
were originally loaded as part of the command.
Although it is possible to modify the code so that it will
abort Workbench objects, tasks in general, interrupt handlers
and servers, etc, one application that I find tantalizing is to
investigate locked up commands "on the fly", ie, while it is
actually running. By modifying ABORTCOMMAND and using your
favourite debugger as if you are debugging your modified
ABORTCOMMAND, you can invesigate the state of the locked up
command at some instant during its execution, perhaps following
its progress in nearly real time (I can't say what can actually
be done since I don't know the nature of your debugger). By
setting up break-points within your modified ABORTCOMMAND, you
can look at the stored registers within segment, donated_segment,
to see exactly what is happening. In such a case it may be
desirable to assemble section, donated_segment, separately
using the symbol dump option (this is why each register storage
location has its own label even though the labels are not
referenced at all by my code). A more sophisticated way would
be to modify ABORTCOMMAND so that it lists all the register
values to a window. To modify ABORTCOMMAND to perform debugging
operations, do not allow the code to transfer "donated_segment"
or modify the task's stored stack frame. Also, remember that
interrupts are disabled throughout most of the code's operation,
so you will be well advised to enable interrupts before doing
anything that requires multitasking. I hope you find this
information useful and that you enjoy using ABORTCOMMAND.
Ken White
~~~~~~~~~
THE END
~~~~~~~